use crate::{
    block::{Diffculty::*, *},
    map::*,
    matrix::*,
    stage::{get_fill_stages, BlockFillStage},
};
use std::cmp;
use tge::util::Rand;
// use std::time::Instant;
use log::info;

// weight<=0表示此块不可用
#[derive(Debug)]
pub struct BlockGenWeight {
    pub index: usize,
    pub weight: i32,
}

// 填充结构
#[derive(Default, Debug, Clone, Copy)]
pub struct BlockFillItem {
    pub block_index: usize,
    pub father_block: usize, // 放置父块ID
    pub fc: i32,             // 放置父块行
    pub fj: i32,             // 放置父块列
    pub ff: i32,             // 放置父块可消除行数
    pub pc: i32,             // 放置行
    pub pj: i32,             // 放置列
    pub area: i64,           // 放置后连续区域大小
    pub fill_full: i32,      // 放置后可消除行和列数
    pub score: i64,
}

impl BlockFillItem {
    // fill为true表示鼓励消行,false表示不鼓励消行
    pub fn update_score(&mut self, fill: bool) {
        let m = if fill { 1 } else { -1 };
        self.score = self.fill_full as i64 * 100000 * m + self.area as i64;
    }
}

#[derive(PartialEq)]
pub enum CalcState {
    NeedFill,
    Pass1Ok,
    Pass2Ok,
    FillOk,
    Idle,
}

pub struct BlockFillMaster {
    pub rand: Rand,
    pub block_group: Vec<Vec<BlockGenWeight>>,
    pub ret: Vec<u8>,
    pub ret_multi_clear: Vec<u8>,
    pub ret_all_clear: Vec<u8>,
    pub cstate: CalcState,
    pub task_per_frame: u8,
    pub stage: u8,
    pub stages: Vec<BlockFillStage>,
    pub msg_debug: String,
    pub score_diff: Vec<i32>,
    count_pass2: u64,
    backup_map: Map,
    result_1pass: Vec<BlockFillItem>,
    result_2pass: Vec<BlockFillItem>,
}

impl BlockFillMaster {
    pub fn new(task_per_frame: u8) -> Self {
        let mut bgs = vec![];
        for i in 0..2 {
            let mut bg = vec![];
            for i in 1..=50 {
                bg.push(BlockGenWeight {
                    index: i,
                    weight: 100,
                });
            }
            let except_ids = if i == 0 {
                vec![42, 43, 44, 45, 46, 47, 48, 49, 50]
            } else {
                vec![1, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50]
            };
            for ei in &except_ids {
                bg[*ei as usize - 1].weight = 0;
            }
            bgs.push(bg);
        }
        let mut r = Rand::new();
        r.srand_now();

        Self {
            rand: r,
            block_group: bgs,
            ret: vec![],
            ret_all_clear: vec![],
            ret_multi_clear: vec![],
            cstate: CalcState::Idle,
            task_per_frame,
            stage: 0,
            stages: get_fill_stages(),
            count_pass2: 0,
            msg_debug: "".to_string(),
            backup_map: Default::default(),
            result_1pass: vec![],
            result_2pass: vec![],
            score_diff: vec![2500i32, 3000i32, 6000i32, 9000i32],
        }
    }
    pub fn set_score_diff(&mut self, arr: Vec<i32>) {
        self.score_diff = arr;
    }

    // 2500分之前为stage0，各种出块都比较容易
    // 2500分到3000分为stage1，比较难
    // 3000分以上stage2，难
    pub fn update_stage(&mut self) {
        if self.backup_map.hard_type == 0 {
            // 如果hard_type为0就不调整难度
            return;
        }
        let cas = self.backup_map.clear_all_score;
        let randism;
        if self.score_diff[0] < 99 {
            randism = 10
        } else if self.score_diff[0] < 999 {
            randism = 100
        } else if self.score_diff[0] < 9999 {
            randism = 1000
        } else {
            randism = 10000
        }
        let sr = self.rand.rand() % randism;
        let s = sr as i32 - (randism / 2) as i32;
        let consider_stage_count = self.score_diff.len(); // 开放的难度级别
        self.stage = 0;
        for i in 0..consider_stage_count {
            // 从分数字段判断
            if self.backup_map.hard_type == 1 && self.backup_map.score > 0 {
                let upper_score = self.score_diff[i];
                let new_upper = (upper_score + s) as u32;
                if self.backup_map.score <= new_upper {
                    self.stage = i as u8;
                    break;
                }
            }
            // 从收集物数量判断
            if self.backup_map.hard_type == 2 && self.backup_map.collection > 0 {
                let upper_collection = self.score_diff[i];
                let new_upper = (upper_collection + s) as u32;
                if self.backup_map.collection <= new_upper {
                    self.stage = i as u8;
                    break;
                }
            }
        }

        // 如果当前得分比开放的最高难度分数还高，就直接最高难度
        if self.backup_map.hard_type == 1
            && self.backup_map.score > self.score_diff[consider_stage_count - 1] as u32
        {
            self.stage = (consider_stage_count - 1) as u8
        } else if self.backup_map.hard_type == 2
            && self.backup_map.collection > self.score_diff[consider_stage_count - 1] as u32
        {
            self.stage = (consider_stage_count - 1) as u8
        }

        // 如果有难度偏移量就加上，但要保证不超界
        if self.backup_map.hard_level > 0 {
            if self.stage + self.backup_map.hard_level as u8 <= (consider_stage_count - 1) as u8 {
                self.stage += self.backup_map.hard_level as u8
            } else {
                self.stage = (consider_stage_count - 1) as u8
            }
        } else if self.backup_map.hard_level < 0 {
            // 小于0的情况，要降档
            if self.stage as i8 + self.backup_map.hard_level >= 0 {
                self.stage = (self.stage as i8 + self.backup_map.hard_level) as u8
            } else {
                self.stage = 0
            }
        }
        // if self.backup_map.score <= (self.score_diff[0] + s) as u32 {
        //     self.stage = 0;
        // } else if self.backup_map.score <= (self.score_diff[1] + s) as u32 {
        //     self.stage = 1;
        // } else if self.backup_map.score <= (self.score_diff[2] + s) as u32 {
        //     self.stage = 2;
        // } else {
        //     self.stage = 3;
        // }
        if cas != 0 {
            self.stages[4] = self.stages[self.stage as usize].clone();
            self.stages[4].pass2_calc3_rate = 0;
            self.stage = 4;
        }
    }

    pub fn cur_stage(&self) -> &BlockFillStage {
        if (self.stage as usize) < self.stages.len() {
            &self.stages[self.stage as usize]
        } else {
            &self.stages[0]
        }
    }

    pub fn fill_reset(&mut self) {
        if self.cstate != CalcState::Idle {
            self.cstate = CalcState::Idle;
            let mut r = Rand::new();
            r.srand_now();
            self.rand = r;
            self.result_1pass = vec![];
            self.result_2pass = vec![];
            self.ret = vec![];
            self.ret_all_clear = vec![];
            self.ret_multi_clear = vec![];
        }
    }

    pub fn fill_request(&mut self, map: &mut Map) -> u8 {
        if self.cstate != CalcState::Idle {
            self.msg_debug = String::from("csstate is not idle");
            return 0;
        }
        self.backup_map = map.clone();
        self.cstate = CalcState::NeedFill;
        self.stages = get_fill_stages();
        self.update_stage();
        let st = self.cur_stage();
        let rate1 = st.rand_rate;
        let rate2 = st.rand_rate + st.pass1_rate;
        let sr = (self.rand.rand() % 1000) as u16;
        let str = format!("sr:{} rate1: {} rate2:{}", sr, rate1, rate2);
        if sr < rate1 {
            self.fill_rand();
            self.cstate = CalcState::FillOk;
            self.msg_debug = format!("fill_type:{} {}", "fill_rand", str.to_string());
            return 1;
        } else if sr < rate2 {
            self.fill_pass1(2);
            self.cstate = CalcState::FillOk;
            self.msg_debug = format!("fill_type:{} {}", "fill_pass1", str.to_string());
            return 2;
        } else {
            // 不执行任何代码，则启动pass2的分帧计算
            self.msg_debug = format!("fill_type:{} {}", "fill_pass2", str.to_string());
            return 3;
        }
        // info!("start fill frame...");
    }
    pub fn fill_revive(&mut self, map: &mut Map) -> u8 {
        if self.cstate != CalcState::Idle {
            self.msg_debug = String::from("csstate is not idle");
            return 0;
        }
        self.backup_map = map.clone();
        self.cstate = CalcState::NeedFill;
        self.stage = 0;
        self.stages = vec![BlockFillStage {
            id: 0,
            rand_rate: 0,
            pass1_rate: 0,
            pass2_rate: 1000,
            pass2_calc3_rate: 0,
            iter_no_big: 1000,
            // good, flat, easy, medium, hard
            good_block_rate: [
                [0, 0, 0, 1000, 0, 0, 0, 0],
                [0, 0, 0, 1000, 0, 0, 0, 0],
                [0, 0, 0, 1000, 0, 0, 0, 0],
            ],
            rand_block_rate: [
                [0, 0, 0, 1000, 0, 0, 0, 0],
                [0, 0, 0, 1000, 0, 0, 0, 0],
                [0, 0, 0, 1000, 0, 0, 0, 0],
            ],
        }];
        // 不执行任何代码，则启动pass2的分帧计算
        self.msg_debug = format!("fill_type:{}", "fill_pass2 when revive");
        return 3;
        // info!("start fill frame...");
    }

    pub fn fill_pass1(&mut self, count: usize) {
        let mut r1pass = self.iter_blocks(true);
        r1pass.sort_by(|a, b| b.score.cmp(&a.score));
        let cnt = cmp::min(count, r1pass.len());
        self.fill_good();
        for i in 0..cnt {
            self.ret[i] = r1pass[i].block_index as u8;
        }
    }

    pub fn fill_pass2_frame(&mut self) {
        let task_per_frame = self.task_per_frame;
        match self.cstate {
            CalcState::NeedFill => {
                self.result_1pass = self.iter_blocks(false);
                self.result_2pass = vec![];
                self.cstate = CalcState::Pass1Ok;
            }
            CalcState::Pass1Ok => {
                for _i in 0..task_per_frame {
                    if self.result_1pass.len() > 0 {
                        let f = self.result_1pass.pop().unwrap();
                        let backup = self.backup_map.grid.clone();
                        // 放下第一块
                        self.backup_map
                            .put_down(f.block_index as u8, f.pc as u8, f.pj as u8, false)
                            .unwrap();
                        self.backup_map.full_updated = false;
                        self.backup_map.clear_full();

                        // 排除本块，避免推重复块
                        let bi = f.block_index as usize - 1;
                        self.block_group[0][bi].weight = 0;
                        self.block_group[1][bi].weight = 0;
                        // 两次鼓励消行接一次鼓励填空...
                        let mut r2 = self.iter_blocks(self.count_pass2 % 3 != 0);
                        self.count_pass2 += 1;
                        // 恢复
                        self.block_group[0][bi].weight = 100;
                        self.block_group[1][bi].weight = 100;

                        r2.sort_by(|a, b| b.score.cmp(&a.score));
                        if r2.len() > 0 {
                            let mut item = r2[0];
                            item.father_block = f.block_index;
                            item.fc = f.pc;
                            item.fj = f.pj;
                            item.ff = f.fill_full;
                            self.result_2pass.push(item);
                        }
                        self.backup_map.grid = backup.clone();
                    }
                    if self.result_1pass.len() == 0 {
                        self.cstate = CalcState::Pass2Ok;
                        break;
                    }
                }
            }
            CalcState::Pass2Ok => {
                self.fill_good();
                if self.result_2pass.len() > 0 {
                    self.result_2pass.sort_by(|a, b| b.score.cmp(&a.score));
                    let r2 = &self.result_2pass[0].clone();
                    self.ret[0] = r2.block_index as u8;
                    self.ret[1] = r2.father_block as u8;
                    let sr = (self.rand.rand() % 1000) as u16;
                    let c3rate = self.cur_stage().pass2_calc3_rate;
                    if sr < c3rate {
                        self.ret_all_clear.clear();
                        self.ret_multi_clear.clear();
                        //放下第一块
                        self.backup_map
                            .put_down(r2.father_block as u8, r2.fc as u8, r2.fj as u8, false)
                            .unwrap();
                        self.backup_map.full_updated = false;
                        let (allc, _crc) = self.backup_map.clear_full();
                        if allc != 0 && self.ret_all_clear.len() == 0 {
                            self.ret_all_clear.push(r2.father_block as u8);
                            self.ret_all_clear.push(r2.fc as u8);
                            self.ret_all_clear.push(r2.fj as u8);
                            self.ret_all_clear.push(r2.ff as u8);
                            info!("$$$$$$$$$CLEAR_ALL{:?}", self.ret_all_clear);
                        }
                        // 第一块先不判断多消
                        // if crc >= 3 && self.ret_multi_clear.len() == 0 {
                        //     self.ret_multi_clear.push(r2.father_block as u8);
                        //     self.ret_multi_clear.push(r2.fc as u8);
                        //     self.ret_multi_clear.push(r2.fj as u8);
                        //     info!("$$$$$$$$$CLEAR_MULTI{} {:?}", crc, self.ret_multi_clear);
                        // }
                        //放下第二块
                        self.backup_map
                            .put_down(r2.block_index as u8, r2.pc as u8, r2.pj as u8, false)
                            .unwrap();
                        self.backup_map.full_updated = false;
                        let (allc, crc) = self.backup_map.clear_full();
                        if allc != 0 && self.ret_all_clear.len() == 0 {
                            self.ret_all_clear.push(r2.father_block as u8);
                            self.ret_all_clear.push(r2.fc as u8);
                            self.ret_all_clear.push(r2.fj as u8);
                            self.ret_all_clear.push(r2.ff as u8);
                            self.ret_all_clear.push(r2.block_index as u8);
                            self.ret_all_clear.push(r2.pc as u8);
                            self.ret_all_clear.push(r2.pj as u8);
                            self.ret_all_clear.push(r2.fill_full as u8);
                            info!("$$$$$$$$$CLEAR_ALL{:?}", self.ret_all_clear);
                        }
                        if crc >= 3 && self.ret_multi_clear.len() == 0 {
                            self.ret_multi_clear.push(r2.father_block as u8);
                            self.ret_multi_clear.push(r2.fc as u8);
                            self.ret_multi_clear.push(r2.fj as u8);
                            self.ret_multi_clear.push(r2.ff as u8);
                            self.ret_multi_clear.push(r2.block_index as u8);
                            self.ret_multi_clear.push(r2.pc as u8);
                            self.ret_multi_clear.push(r2.pj as u8);
                            self.ret_multi_clear.push(r2.fill_full as u8);
                            info!("$$$$$$$$$CLEAR_MULTI{} {:?}", crc, self.ret_multi_clear);
                        }
                        let mut res2 = self.iter_blocks(true);
                        let mut r2x = 0u8;
                        let mut r2y = 0u8;
                        let mut r2ff = 0u8;
                        res2.sort_by(|a, b| b.score.cmp(&a.score));
                        if res2.len() > 1 {
                            if sr % 2 == 0 {
                                let item = res2[0];
                                self.ret[2] = item.block_index as u8;
                                r2x = item.pc as u8;
                                r2y = item.pj as u8;
                                r2ff = item.fill_full as u8;
                            } else {
                                let item = res2[1];
                                self.ret[2] = item.block_index as u8;
                                r2x = item.pc as u8;
                                r2y = item.pj as u8;
                                r2ff = item.fill_full as u8;
                            }
                        } else if res2.len() > 0 {
                            let item = res2[0];
                            self.ret[2] = item.block_index as u8;
                            r2x = item.pc as u8;
                            r2y = item.pj as u8;
                            r2ff = item.fill_full as u8;
                        }
                        //放下第三块
                        self.backup_map
                            .put_down(self.ret[2], r2x as u8, r2y as u8, false)
                            .unwrap();
                        self.backup_map.full_updated = false;
                        let (allc, crc) = self.backup_map.clear_full();
                        if allc != 0 && self.ret_all_clear.len() == 0 {
                            self.ret_all_clear.push(r2.father_block as u8);
                            self.ret_all_clear.push(r2.fc as u8);
                            self.ret_all_clear.push(r2.fj as u8);
                            self.ret_all_clear.push(r2.ff as u8);
                            self.ret_all_clear.push(r2.block_index as u8);
                            self.ret_all_clear.push(r2.pc as u8);
                            self.ret_all_clear.push(r2.pj as u8);
                            self.ret_all_clear.push(r2.fill_full as u8);
                            self.ret_all_clear.push(self.ret[2] as u8);
                            self.ret_all_clear.push(r2x as u8);
                            self.ret_all_clear.push(r2y as u8);
                            self.ret_all_clear.push(r2ff as u8);
                            info!("$$$$$$$$$CLEAR_ALL{:?}", self.ret_all_clear);
                        }
                        if crc >= 3 && self.ret_multi_clear.len() == 0 {
                            self.ret_multi_clear.push(r2.father_block as u8);
                            self.ret_multi_clear.push(r2.fc as u8);
                            self.ret_multi_clear.push(r2.fj as u8);
                            self.ret_multi_clear.push(r2.ff as u8);
                            self.ret_multi_clear.push(r2.block_index as u8);
                            self.ret_multi_clear.push(r2.pc as u8);
                            self.ret_multi_clear.push(r2.pj as u8);
                            self.ret_multi_clear.push(r2.fill_full as u8);
                            self.ret_multi_clear.push(self.ret[2] as u8);
                            self.ret_multi_clear.push(r2x as u8);
                            self.ret_multi_clear.push(r2y as u8);
                            self.ret_multi_clear.push(r2ff as u8);
                            info!("$$$$$$$$$CLEAR_MULTI{} {:?}", crc, self.ret_multi_clear);
                        }
                    }
                }
                self.rand.shuffle(&mut self.ret);
                if self.backup_map.score < 100 || self.stage == 4 {
                    for i in 0..3 {
                        if self.ret[i] == 41 {
                            let sr2 = (self.rand.rand() % 1000) as u16;
                            if sr2 < 800 {
                                let bs = [39, 40, 16u8];
                                self.ret[i] = bs[(sr2 % 3) as usize];
                                break;
                            }
                        }
                    }
                }
                // info!("ret....{:?}", self.ret);
                self.cstate = CalcState::FillOk;
                self.msg_debug = format!("fill_pass2").to_string();
            }
            CalcState::FillOk => {}
            CalcState::Idle => {}
        }
    }

    pub fn get_block(&mut self, d: Diffculty) {
        let mv = get_blocks(d);
        self.ret.push(mv[self.rand.rand() as usize % mv.len()]);
    }

    // good, flat, easy, medium, hard
    pub fn get_block_rate(&mut self, r: &[u16; 8]) {
        let sr = (self.rand.rand() % 1000) as u16;
        if sr < r[0] {
            self.get_block(Good);
        } else if sr < r[0] + r[1] {
            self.get_block(Flat);
        } else if sr < r[0] + r[1] + r[2] {
            self.get_block(Easy);
        } else if sr < r[0] + r[1] + r[2] + r[3] {
            self.get_block(Medium);
        } else if sr < r[0] + r[1] + r[2] + r[3] + r[4] {
            self.get_block(Hard);
        } else {
            self.get_block(HardEx);
        }
    }

    pub fn fill_good(&mut self) {
        self.ret.clear();
        for i in 0..3 {
            self.get_block_rate(&self.cur_stage().good_block_rate[i].clone());
        }
        self.rand.shuffle(&mut self.ret);
    }

    pub fn fill_rand(&mut self) {
        self.ret.clear();
        for i in 0..3 {
            self.get_block_rate(&self.cur_stage().rand_block_rate[i].clone());
        }
        self.rand.shuffle(&mut self.ret);
    }

    // 根据当前布局
    // 遍历所有块和位置,得到较好的填充结构
    // fill为true鼓励消行,用于1层推荐
    // fill为false不鼓励消行，用于2层推荐时推荐第一块
    fn iter_blocks(&mut self, fill: bool) -> Vec<BlockFillItem> {
        let n = 8;
        let matrix = grid_to_bin(&self.backup_map.grid, n);
        let mut temp_matrix = matrix.clone();
        let (raw_max_area, _) = matrix_calc(&mut temp_matrix, n, n);

        let srb = (self.rand.rand() % 1000) as u16;
        let bgid = if srb < self.cur_stage().iter_no_big {
            1
        } else {
            0
        };
        let mut results = Vec::new();
        for block in &self.block_group[bgid] {
            if block.weight <= 0 {
                continue;
            }
            let bid = block.index;
            let mut bfis = vec![];
            for i in 0..n as u8 {
                for j in 0..n as u8 {
                    if let Ok(is_can_put) = self.backup_map.put_down(bid as u8, i, j, true) {
                        if !is_can_put {
                            continue;
                        }
                    } else {
                        continue;
                    }
                    let mut temp_matrix = matrix.clone();
                    matrix_put_down(&mut temp_matrix, bid as u8, i, j);
                    let (max_area, fill_full) = matrix_calc(&mut temp_matrix, n, n);
                    let mut bf = BlockFillItem {
                        block_index: bid,
                        father_block: 0,
                        fc: 0,
                        fj: 0,
                        ff: 0,
                        pc: i as i32,
                        pj: j as i32,
                        area: max_area as i64 - raw_max_area as i64,
                        fill_full: fill_full as i32,
                        score: 0,
                    };
                    bf.update_score(fill);
                    bfis.push(bf);
                }
            }
            bfis.sort_by(|a, b| b.score.cmp(&a.score));
            // let mut need = if fill { 1 } else { 2 };
            let mut need = 5;
            need = cmp::min(need, bfis.len());
            // info!("NEED...{}", need);
            for n in 0..need {
                results.push(bfis[n]);
            }
        }
        results.sort_by(|a, b| b.score.cmp(&a.score));
        let mut need = if fill { 50 } else { 100 };
        need = cmp::min(need, results.len());
        results.truncate(need);
        results
    }

    pub fn update(&mut self) {
        self.fill_pass2_frame();
    }
}
